package com.google.code.gwtmvpscaffold;

import static com.google.code.gwtmvpscaffold.SystemVariables.PATH;
import static com.google.code.gwtmvpscaffold.SystemVariables.SEP;

import java.io.File;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.antlr.stringtemplate.StringTemplate;

import com.google.common.collect.Maps;

/**
 * 
 * @author Ismet Ozalp
 * 
 */
public class MVPScaffold {

  private final Pattern variableGroupPattern = Pattern.compile(".*^\\$(.*)\\$.*");
  private final String outputPath;
  private final String projectName;
  private final String packageName;
  private final Paths path;
  private final String compatibleName;

  private Map<String, String> globalVariableMap = Maps.newHashMap();

  public MVPScaffold(Paths path, String outputPath, String projectName, String packageName) {
    this.outputPath = outputPath;
    this.projectName = projectName;
    this.packageName = packageName;
    this.path = path;

    String aCompatibleName = projectName;
    if (projectName.contains(".")) {
      aCompatibleName = "";
      String[] split = projectName.split("\\.");
      for (String string : split) {
        char[] charArray = string.toCharArray();
        charArray[0] = Character.toUpperCase(charArray[0]);
        aCompatibleName += String.valueOf(charArray);
      }
    }
    globalVariableMap.put("PROJECT_NAME_CLASS_NAME_COMPATIBLE", aCompatibleName);
    globalVariableMap.put("PROJECT_NAME_CLASS_NAME_COMPATIBLE_LOWER_CASE",
        aCompatibleName.toLowerCase());
    this.compatibleName = aCompatibleName;
    globalVariableMap.put("PROJECT_NAME", projectName);
    globalVariableMap.put("PACKAGE_NAME", packageName);
    globalVariableMap.put("DOT", ".");
  }

  public void changeSingleTemplate(File f) {
    String filePath = f.getAbsolutePath();
    String fileName = f.getName();

    if (matchAndChangeTemplate(fileName, filePath)) {
      String contents = Utils.readFileToString(f.getAbsolutePath());
      if (validateVariablesOnNewTemplate(f.getName(), contents)) {
        processTemplates();
      }
    }
  }

  protected boolean validateVariablesOnNewTemplate(String fname, String contents) {
    Map<String, String> fileMap = Variables.variableMap.get(fname);
    Set<String> variables = fileMap.keySet();
    for (String variable : variables) {
      if (!contents.contains(variable)) {
        System.out.println("Template " + fname + " does not have variable:" + variable);
        return false;
      }
    }
    return true;
  }

  protected boolean matchAndChangeTemplate(String fileName, String filePath) {
    if (path.TEMPLATE_FILES_INPUT_PATH.containsKey(fileName)) {
      path.TEMPLATE_FILES_INPUT_PATH.put(fileName, filePath);
      return true;
    }

    System.out.println("There is no template file named:" + fileName);
    return false;
  }

  public void changeMultipleTemplatesUsingZipFile(File f) {
    processTemplates();
  }

  public void useOnlyDefaultTemplates() {
    processTemplates();
    createZip();
    doCleanUp();
  }

  protected boolean processTemplates() {
    StringTemplate template = null;

    Map<String, String> templateFilesInputPath = path.TEMPLATE_FILES_INPUT_PATH;
    Set<String> files = templateFilesInputPath.keySet();
    for (String fileName : files) {
      Map<String, String> fileVariables = Variables.variableMap.get(fileName);
      if (fileVariables == null) {
        return false;
      }
      String fileInputPath = templateFilesInputPath.get(fileName);
      String fileOutputPath = path.TEMPLATE_FILES_OUTPUT_PATH.get(fileName);
      String contents = "";
      if (fileInputPath.length() == 0) {
        contents = Utils.readFromResouce(fileName + ".tpl");
      } else {
        contents = Utils.readFileToString(fileInputPath + SEP + fileName + ".tpl");
      }

      Matcher matcher = variableGroupPattern.matcher(fileName);
      if (matcher.find()) {
        String fnameVariable = matcher.group(1);

        String fnameValue = globalVariableMap.get(fnameVariable);
        if (fnameValue == null) {
          System.out.println("Unknown variable:" + fnameVariable);
          return false;
        }

        template = new StringTemplate(fileName);
        template.setAttribute(fnameVariable, fnameValue);
        fileName = template.toString();
      }

      Set<String> variableSet = fileVariables.keySet();
      if (variableSet == null) {
        return false;
      }
      template = new StringTemplate(contents);
      for (String variableName : variableSet) {
        String variableValue = globalVariableMap.get(variableName);
        if (variableValue == null) {
          System.out.println("Variable:" + variableName
              + " not found in globalVariableMap. It seems you forgot to set it.");
          return false;
        }
        template.setAttribute(variableName, variableValue);
      }

      String compiledTemplate = template.toString();

      String finalPath = PATH + SEP + compatibleName + SEP + fileOutputPath + SEP + fileName;
      Utils.writeToFile(compiledTemplate, finalPath);
    }
    Utils.createDirectory(PATH + SEP + compatibleName + SEP + "src" + SEP + "test" + SEP + "java");
    return true;
  }

  protected boolean createZip() {
    try {
      Utils.zipDir(outputPath + SEP + compatibleName + ".zip", PATH + SEP + compatibleName);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  protected boolean doCleanUp() {
    return Utils.deleteDir(new File(PATH + SEP + compatibleName));
  }
}
